home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / others / ole_101.zip / PATRON.ZIP / OLELINK1.C < prev    next >
C/C++ Source or Header  |  1992-04-13  |  29KB  |  951 lines

  1. /*
  2.  * OLELINK1.C
  3.  *
  4.  * Functions to handle the Edit Links command as well as the
  5.  * Links dialog.
  6.  *
  7.  * Copyright(c) Microsoft Corp. 1992 All Rights Reserved
  8.  */
  9.  
  10.  
  11. #include <windows.h>
  12. #include <ole.h>
  13. #include "register.h"
  14. #include "oclient.h"
  15.  
  16.  
  17.  
  18.  
  19.  
  20. /*
  21.  * FOLELinksEdit
  22.  *
  23.  * Purpose:
  24.  *  Handles the Links dialog and the Update Now, Cancel Link, and
  25.  *  Change Link commands.
  26.  *
  27.  * Parameters:
  28.  *  hWnd            HWND of the parent window.
  29.  *  hInst           HANDLE of the application instance.
  30.  *  pDoc            LPDOCUMENT to OLE information.
  31.  *
  32.  * Return Value:
  33.  *  BOOL            FALSE if we could not create the dialog or if
  34.  *                  the user pressed Cancel.  TRUE otherwise.
  35.  */
  36.  
  37. BOOL FAR PASCAL FOLELinksEdit(HWND hWnd, HANDLE hInst, LPDOCUMENT pDoc)
  38.     {
  39.     FARPROC         lpfn;
  40.     WORD            wRet;
  41.  
  42.     lpfn=MakeProcInstance(LinksProc, hInst);
  43.     wRet=DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_LINKS), hWnd,
  44.                         lpfn, (LONG)pDoc);
  45.     FreeProcInstance(lpfn);
  46.  
  47.     return (1==wRet);
  48.     }
  49.  
  50.  
  51.  
  52.  
  53.  
  54. /*
  55.  * LinksProc
  56.  *
  57.  * Purpose:
  58.  *  Dialog procedure for the Links dialog.
  59.  *
  60.  * Parameters:
  61.  *  The standard.
  62.  *
  63.  * Return Value:
  64.  *  The value to be returned through the DialogBox call that
  65.  *  created the dialog.
  66.  */
  67.  
  68. BOOL FAR PASCAL LinksProc(HWND hDlg, WORD iMsg, WORD wParam, LONG lParam)
  69.     {
  70.     static LPDOCUMENT   pDoc;
  71.     HWND                hList;
  72.     WORD                cxTabs[3];
  73.     RECT                rc;
  74.     WORD                cx;
  75.     DWORD               dwBase;
  76.     OLEOPT_UPDATE       dwUpdate;
  77.  
  78.     hList=GetDlgItem(hDlg, ID_LINKLIST);
  79.  
  80.     switch (iMsg)
  81.         {
  82.         case WM_INITDIALOG:
  83.             pDoc=(LPDOCUMENT)lParam;
  84.             pDoc->hList=hList;
  85.  
  86.             //Initialize tabstops, each at 1/4 of the listbox width.
  87.             GetClientRect(hList, &rc);
  88.  
  89.             //Pixel width of a tab.  Put in pDoc->cxList for CchListStringCreate.
  90.             pDoc->cxList=((rc.right-rc.left) >> 2)-8;
  91.  
  92.             //Convert pixel width to dialog width for LB_SETTABSTOPS
  93.             dwBase=GetDialogBaseUnits();
  94.             cx=((rc.right-rc.left) * 4)/LOWORD(dwBase);
  95.             cxTabs[0]=cx >> 2;
  96.             cxTabs[1]=cx >> 1;
  97.             cxTabs[2]=(cx * 3) >> 2;
  98.  
  99.             SendMessage(hList, LB_SETTABSTOPS, 3, (LONG)(LPSTR)&cxTabs);
  100.  
  101.             //Initialize listbox strings.
  102.             if (!FObjectsEnumerate(pDoc, FEnumLinksInit, 0L))
  103.                 EndDialog(hDlg, -1);
  104.  
  105.             //Select the first listbox string.
  106.             SendMessage(hList, LB_SETSEL, 1, 0L);
  107.  
  108.             EnableLinkButtons(hDlg, hList);
  109.             return TRUE;
  110.  
  111.  
  112.         case WM_COMMAND:
  113.             switch (wParam)
  114.                 {
  115.                 case ID_UPDATENOW:
  116.                     /*
  117.                      * If we're updating, just enumerate selected links and
  118.                      * let FEnumLinkUpdate take care of finding other matching
  119.                      * unselected links and updating them.
  120.                      */
  121.                     FLinksEnumerate(hList, pDoc, FEnumLinkUpdate,
  122.                                     ENUMLINK_SELECTED, MAKELONG(0, IDOK));
  123.  
  124.                     //Insure that the fNoMatch flags are reset.
  125.                     FLinksEnumerate(hList, pDoc, FEnumLinkUpdate, ENUMLINK_ALL,
  126.                                     MAKELONG(0, IDCANCEL));
  127.  
  128.                     EnableLinkButtons(hDlg, hList);
  129.                     break;
  130.  
  131.                 case ID_CANCELLINK:
  132.                     FLinksEnumerate(hList, pDoc, FEnumLinkCancel,
  133.                                     ENUMLINK_SELECTED, 0L);
  134.                     EnableLinkButtons(hDlg, hList);
  135.                     break;
  136.  
  137.                 case ID_CHANGELINK:
  138.                     FChangeLinks(hList, pDoc);
  139.                     EnableLinkButtons(hDlg, hList);
  140.                     break;;
  141.  
  142.                 case ID_UPDATEAUTO:
  143.                 case ID_UPDATEMANUAL:
  144.                     dwUpdate=(ID_UPDATEAUTO==wParam) ? oleupdate_always : oleupdate_oncall;
  145.  
  146.                     if (0L!=SendMessage(LOWORD(lParam), BM_GETCHECK, 0, 0L))
  147.                         {
  148.                         FLinksEnumerate(hList, pDoc, FEnumOptionChange,
  149.                                         ENUMLINK_SELECTED, dwUpdate);
  150.                         EnableLinkButtons(hDlg, hList);
  151.                         }
  152.                     break;
  153.  
  154.                 case ID_LINKLIST:
  155.                     if (HIWORD(lParam) == LBN_SELCHANGE)
  156.                         EnableLinkButtons(hDlg, hList);
  157.                     break;
  158.  
  159.                 case IDCANCEL:
  160.                     FLinksEnumerate(hList, pDoc, FEnumLinksUndo,
  161.                                     ENUMLINK_ALL, 0L);
  162.                     EndDialog(hDlg, FALSE);
  163.                     break;
  164.  
  165.                 case IDOK:
  166.                     FLinksEnumerate(hList, pDoc, FEnumLinksAccept,
  167.                                     ENUMLINK_ALL, 0L);
  168.  
  169.                     EndDialog(hDlg, TRUE);
  170.                     break;
  171.                 }
  172.             break;
  173.         }
  174.  
  175.     return FALSE;
  176.     }
  177.  
  178.  
  179.  
  180.  
  181.  
  182. /*
  183.  * FEnumLinksInit
  184.  *
  185.  * Purpose:
  186.  *  For each enumerated object that is linked we build a listbox string
  187.  *  for it and add it to a listbox (the handle is found in pDoc->hList).
  188.  *
  189.  * Parameters:
  190.  *  pDoc            LPDOCUMENT identifying the owner of all objects.
  191.  *  pObj            LPOBJECT identifying the current object.
  192.  *  dw              DWORD for extra data, unused.
  193.  *
  194.  * Return Value:
  195.  *  BOOL            TRUE--we want to enumerate everything.
  196.  */
  197.  
  198. BOOL FAR PASCAL FEnumLinksInit(LPDOCUMENT pDoc, LPOBJECT pObj, DWORD dw)
  199.     {
  200.     static WORD     iClone=0;   //Counter for clone objects.
  201.     WORD            i;
  202.     char            szClone[40];
  203.     OLESTATUS       os;
  204.  
  205.     if (OT_LINK==pObj->dwType)
  206.         {
  207.         /*
  208.          * We already have the ObjectLink data in ATOMs, so just pass the
  209.          * object to CchLinkStringCreate.
  210.          */
  211.         CchLinkStringCreate(pDoc->pszData1, pDoc, pObj);
  212.  
  213.         i=(WORD)SendMessage(pDoc->hList, LB_ADDSTRING, 0, (LONG)pDoc->pszData1);
  214.         SendMessage(pDoc->hList, LB_SETITEMDATA, i, (LONG)(LPSTR)pObj);
  215.  
  216.         //Create a clone name
  217.         wsprintf(szClone, "Clone #%d", iClone);
  218.  
  219.         //Clone the object for Undo on Cancel.
  220.         os=OleClone(pObj->pObj, (LPOLECLIENT)pObj, pDoc->lh, szClone, &pObj->pObjUndo);
  221.  
  222.         //Wait for any one object.
  223.         pDoc->cWait=0;
  224.         OsError(os, pDoc, pObj, FALSE);
  225.         FOLEReleaseWait(TRUE, pDoc, NULL);
  226.  
  227.         //Save the open state of this object.
  228.         os=OleQueryOpen(pObj->pObj);
  229.         pObj->fUndoOpen=(OLE_OK==os);
  230.  
  231.         //Mark this object as clean
  232.         pObj->fLinkChange=FALSE;
  233.         }
  234.  
  235.     iClone++;
  236.     return TRUE;
  237.     }
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244. /*
  245.  * FChangeLinks
  246.  *
  247.  * Purpose:
  248.  *  Retrieve a new link filename from the user and change selected links
  249.  *  to that new file.  Then scan the remaining unselected links and ask
  250.  *  the user to change those as well.  All links will be from the same
  251.  *  original file since the Change Link button is otherwise disabled.
  252.  *
  253.  * Parameters:
  254.  *  hList           HWND to the listbox of link items.
  255.  *  pDoc            LPDOCUMENT containing OLE information.
  256.  *
  257.  * Return Value:
  258.  *  BOOL            TRUE if the function was successful, FALSE on an error
  259.  *                  or if the user pressed Cancel.
  260.  */
  261.  
  262. BOOL FAR PASCAL FChangeLinks(HWND hList, LPDOCUMENT pDoc)
  263.     {
  264.     LPSTR           pszLinkFile;
  265.     LPSTR           pszFile;
  266.     LPSTR           pszExt;
  267.     LPSTR           psz;
  268.     HANDLE          hInst;
  269.     HWND            hWndParent;
  270.     BOOL            fRet;
  271.     ATOM            aFileOld;
  272.     ATOM            aFileNew;
  273.     WORD            cch;
  274.     WORD            wTemp;
  275.     char            szFile[CCHPATHMAX];
  276.  
  277.  
  278.     hWndParent=GetParent(hList);
  279.     hInst=GetWindowWord(hWndParent, GWW_HINSTANCE);
  280.  
  281.     //Find the first selected item and retrieve its ObjectLink data
  282.     FLinksEnumerate(hList, pDoc, FEnumLinkFind, ENUMLINK_SELECTED,
  283.                     MAKELONG(1, 1));
  284.  
  285.     //Chew out a filename from this thing.
  286.     pszFile =pDoc->pszData1 + lstrlen(pDoc->pszData1) + 1;
  287.     lstrcpy(szFile, pszFile);
  288.     aFileOld=AddAtom(pszFile);
  289.     DeleteAtom(aFileOld);
  290.  
  291.     /*
  292.      * Before calling FFileDialog to show the Common Dialog in which
  293.      * we retrieve a new link name, we need to produce one extension
  294.      * string for the currently linked file and produce a Filter string
  295.      * like "Excel Worksheet (.XLS)."  As of 1/27/92 the UI spec shows
  296.      * the application name in the filter combobox, but we have no way
  297.      * of getting that from an extension, unless we're to parse WIN.INI
  298.      * which is out of the question.
  299.      */
  300.  
  301.     //Get a pointer to the extension.
  302.     pszExt=PszExtensionFromFile(pszFile);
  303.  
  304.     /*
  305.      * Create a filter using the extension name with the .  If there
  306.      * is no association between the file extension and a classname
  307.      * and descriptive name in the registration DB, then the two calls
  308.      * into REGISTER.C fail and we just list the extension itself.
  309.      * That's about the best we can do.
  310.      */
  311.     WClassFromExtension(pszExt, pDoc->pszData2, CCHPATHMAX);
  312.     WDescriptionFromClass(pDoc->pszData2, pDoc->pszData1, CCHPATHMAX);
  313.     wsprintf(pDoc->pszData2, " (%s)", pszExt);
  314.     lstrcat(pDoc->pszData1, pDoc->pszData2);
  315.  
  316.     //Skip the . in the extension if we have one.
  317.     if ('.'==*pszExt)
  318.         pszExt++;
  319.  
  320.     fRet=FFileDialog(hWndParent, hInst, pszExt, pDoc->pszData1,
  321.                     szFile, PSZOLE(IDS_CHANGELINK), TRUE);
  322.  
  323.     //Stop if the user cancelled.
  324.     if (!fRet)
  325.         return FALSE;
  326.  
  327.     //Go change the selected links and update them.
  328.     aFileNew=AddAtom(szFile);
  329.     FLinksEnumerate(hList, pDoc, FEnumLinkChange,
  330.                     ENUMLINK_SELECTED, MAKELONG(aFileNew, 0));
  331.  
  332.     FLinksEnumerate(hList, pDoc, FEnumLinkUpdate, ENUMLINK_SELECTED,
  333.                     MAKELONG(0, IDIGNORE));
  334.  
  335.  
  336.     //Find an unselected link that matches.
  337.  
  338.     fRet=FLinksEnumerate(hList, pDoc, FEnumLinkFind,
  339.                          ENUMLINK_UNSELECTED, MAKELONG(aFileOld, 0));
  340.  
  341.     if (fRet)
  342.         {
  343.         DeleteAtom(aFileNew);
  344.         return TRUE;
  345.         }
  346.  
  347.  
  348.     //Ask the user if they want to update the rest to szFile.
  349.     psz=pDoc->pszData2;
  350.     pszLinkFile=PszFileFromPath(szFile);
  351.  
  352.     GetAtomName(pDoc->aFile, pDoc->pszData3, CCHPATHMAX);
  353.     pszFile=PszFileFromPath(pDoc->pszData3);
  354.  
  355.     cch=wsprintf(psz, PSZOLE(IDS_CHANGELINKS1), pszLinkFile, pszFile);
  356.     wsprintf(psz+cch, PSZOLE(IDS_CHANGELINKS2), pszLinkFile);
  357.  
  358.     //Ask to update additional links.
  359.     wTemp=MessageBox(hWndParent, psz, PSZOLE(IDS_CHANGELINK),
  360.                      MB_YESNO | MB_ICONEXCLAMATION);
  361.  
  362.     //If they say yes, then find unselected links that match and change them.
  363.     if (IDYES==wTemp)
  364.         {
  365.         FLinksEnumerate(hList, pDoc, FEnumLinkChange,
  366.                         ENUMLINK_UNSELECTED, MAKELONG(aFileNew, aFileOld));
  367.  
  368.         //We have to change the search ATOM since we changed the link.
  369.         aFileOld=aFileNew;
  370.  
  371.         //Update these changed links.
  372.         FLinksEnumerate(hList, pDoc, FEnumLinkUpdate, ENUMLINK_UNSELECTED,
  373.                         MAKELONG(aFileOld, IDIGNORE));
  374.         }
  375.  
  376.     DeleteAtom(aFileNew);
  377.     return TRUE;
  378.     }
  379.  
  380.  
  381.  
  382.  
  383.  
  384. /*
  385.  * FLinksEnumerate
  386.  *
  387.  * Purpose:
  388.  *  Walks through each items in the list.  If the object is selected
  389.  *  (or NOT selected) and the object is NOT static, then we call a
  390.  *  provided function of type LPFNLINKENUM.
  391.  *
  392.  *  If the enumeration function should always wait for each object.  This
  393.  *  enumeration function will not wait for all objects at the end.
  394.  *
  395.  * Parameters:
  396.  *  hList           HWND of the listbox with the link items
  397.  *  pDoc            LPDOCUMENT containing OLE information.
  398.  *  pfn             LPFNOBJECTENUM to the function to call for
  399.  *                  each item.
  400.  *  wSelection      WORD indicating the type of links to enumerate, either
  401.  *                  ENUMLINK_SELECTED, ENUMLINK_UNSELECTED, or ENUMLINK_ALL.
  402.  *  dwData          DWORD extra data to pass to the enumeration
  403.  *                  function.
  404.  *
  405.  * Return Value:
  406.  *  BOOL            TRUE if we processed all listbox items, FALSE
  407.  *                  if the enumeration function stopped it.
  408.  */
  409.  
  410. BOOL FAR PASCAL FLinksEnumerate(HWND hList, LPDOCUMENT pDoc, LPFNLINKENUM pfn,
  411.                                 WORD wSelection, DWORD dwData)
  412.     {
  413.     WORD            cLinks;
  414.     LPOBJECT        pObj;
  415.     WORD            i;
  416.     BOOL            fSel;
  417.     BOOL            fRet=TRUE;
  418.  
  419.     cLinks=(WORD)SendMessage(hList, LB_GETCOUNT, 0, 0L);
  420.  
  421.     //Loop through the items update non-static ones.
  422.     for (i=0; i < cLinks; i++)
  423.         {
  424.         //Get the selection state of the item
  425.         fSel=(BOOL)SendMessage(hList, LB_GETSEL, i, 0L);
  426.  
  427.         //Get the data pointer for this item.
  428.         pObj=(LPOBJECT)SendMessage(hList, LB_GETITEMDATA, i, 0L);
  429.  
  430.  
  431.         //Match the item found to the type desired and call the callback.
  432.         if (ENUMLINK_ALL!=wSelection && OT_STATIC==pObj->dwType)
  433.             continue;
  434.  
  435.         if ((fSel && ENUMLINK_SELECTED==wSelection) ||
  436.              (!fSel && ENUMLINK_UNSELECTED==wSelection) ||
  437.              (ENUMLINK_ALL==wSelection))
  438.             {
  439.             //Call the enumeration function
  440.             if (!(*pfn)(hList, i, pDoc, pObj, dwData))
  441.                 {
  442.                 fRet=FALSE;
  443.                 break;
  444.                 }
  445.             }
  446.         }
  447.  
  448.     return fRet;
  449.     }
  450.  
  451.  
  452.  
  453.  
  454.  
  455.  
  456. /*
  457.  * FEnumOptionChange
  458.  *
  459.  * Purpose:
  460.  *  Enumeration function for changing selected list items between manual
  461.  *  and automatic.
  462.  *
  463.  * Parameters:
  464.  *  hList           HANDLE to the links listbox.
  465.  *  i               WORD index of the item affected.
  466.  *  pDoc            LPDOCUMENT containing OLE information
  467.  *  pObj            LPOBJECT of the currently enumerated object.
  468.  *  dw              DWORD application supplied extra data
  469.  *
  470.  * Return Value:
  471.  *  BOOL            Always TRUE since we want to process all selected
  472.  *                  items.
  473.  */
  474.  
  475. BOOL FAR PASCAL FEnumOptionChange(HWND hList, WORD i, LPDOCUMENT pDoc,
  476.                                   LPOBJECT pObj, DWORD dw)
  477.     {
  478.     OLESTATUS       os;
  479.  
  480.     /*
  481.      * dw contains the type of link we're changing to, so if this item
  482.      * already matches we can skip it.
  483.      */
  484.  
  485.     if ((OLEOPT_UPDATE)dw==pObj->dwLink)
  486.         return TRUE;
  487.  
  488.  
  489.     /*
  490.      * For any item that changes, call OleSetLinkUpdateOptions
  491.      * to change the link option, change it in the OBJECT structure,
  492.      * and rebuild the string in the list.  Only the link option
  493.      * changes in the object; none of the string nor atoms change.
  494.      */
  495.  
  496.     pObj->dwLink=(OLEOPT_UPDATE)dw;
  497.     os=OleSetLinkUpdateOptions(pObj->pObj, (OLEOPT_UPDATE)dw);
  498.  
  499.     /*
  500.      * We can wait for release later since we won't do any more
  501.      * OLE with this object.  This depends on CchLinkStringCreate NOT
  502.      * calling any OLE functions.
  503.      */
  504.     if (OLE_OK==OsError(os, pDoc, pObj, TRUE))
  505.         {
  506.         CchLinkStringCreate(pDoc->pszData1, pDoc, pObj);
  507.         LinkStringChange(hList, i, pDoc->pszData1);
  508.         pObj->fLinkChange=TRUE;
  509.         }
  510.  
  511.     return TRUE;
  512.     }
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520. /*
  521.  * FEnumLinkUpdate
  522.  *
  523.  * Purpose:
  524.  *  Immediately updates a selected links.  If dw!=0L then the LOWORD
  525.  *  contains an ATOM to compare to link names stored in the objects.
  526.  *  If HIWORD is zero, then any object that matches is updated--otherwise
  527.  *  just compare the atom to the link in the object and mark it as
  528.  *  needing update later.
  529.  *
  530.  * Parameters:
  531.  *  hList           HANDLE to the links listbox.
  532.  *  i               WORD index of the item affected.
  533.  *  pDoc            LPDOCUMENT containing OLE information
  534.  *  pObj            LPOBJECT of the currently enumerated object.
  535.  *  dw              DWORD application supplied extra data.
  536.  *
  537.  * Return Value:
  538.  *  BOOL            Always TRUE since we want to process all selected
  539.  *                  items.
  540.  */
  541.  
  542. BOOL FAR PASCAL FEnumLinkUpdate(HWND hList, WORD i, LPDOCUMENT pDoc,
  543.                                 LPOBJECT pObj, DWORD dw)
  544.     {
  545.     LPSTR           psz;
  546.     LPSTR           pszLinkFile;
  547.     LPSTR           pszFile;
  548.     BOOL            fRet;
  549.     WORD            wTemp;
  550.     DWORD           dwT;
  551.     WORD            cch;
  552.     HWND            hWndParent;
  553.     OLESTATUS       os;
  554.  
  555.  
  556.     switch (HIWORD(dw))
  557.         {
  558.         case IDIGNORE:
  559.             if (0!=LOWORD(dw))
  560.                 {
  561.                 //Skip items that do not match.
  562.                 if (LOWORD(dw)!=pObj->aLink)
  563.                     return TRUE;
  564.                 }
  565.             break;
  566.  
  567.         case IDRETRY:
  568.             /*
  569.              * We only use this for selected items...if the links match, set
  570.              * fNoMatch so we don't try to find matching unselected links
  571.              * later.
  572.              */
  573.             if (LOWORD(dw)==pObj->aLink)
  574.                 pObj->fNoMatch=TRUE;
  575.  
  576.             return TRUE;
  577.  
  578.         case IDCANCEL:
  579.             //Clear pObj->fNoMatch
  580.             pObj->fNoMatch=FALSE;
  581.             return TRUE;
  582.         }
  583.  
  584.     os=OleUpdate(pObj->pObj);
  585.     os=OsError(os, pDoc, pObj, TRUE);
  586.  
  587.     //Mark the object as changed.
  588.     pObj->fLinkChange=TRUE;
  589.  
  590.     /*
  591.      * If update failed, mark as unavailable.  Otherwise change unavailable
  592.      * links back to automatic.
  593.      */
  594.     dwT=pObj->dwLink;
  595.  
  596.     if (OLE_OK!=os)
  597.         pObj->dwLink=OLEUPDATE_UNAVAILABLE;
  598.     else
  599.         {
  600.         if (OLEUPDATE_UNAVAILABLE==pObj->dwLink)
  601.             pObj->dwLink=oleupdate_always;
  602.         }
  603.  
  604.     //Change the listbox if the option changed.
  605.     if ((DWORD)pObj->dwLink!=dwT)
  606.         {
  607.         CchLinkStringCreate(pDoc->pszData1, pDoc, pObj);
  608.         LinkStringChange(hList, i, pDoc->pszData1);
  609.         }
  610.  
  611.     //If we were just updating, we can leave now.
  612.     if (IDIGNORE==HIWORD(dw))
  613.         return TRUE;
  614.  
  615.  
  616.     /*
  617.      * If we already updated other unselected links for this file, then
  618.      * don't ask the user again.  We change this flag for selected items
  619.      * the first time we update unselected matching items.
  620.      */
  621.     if (pObj->fNoMatch)
  622.         return TRUE;
  623.  
  624.     //Find any unselected link that matches this file.
  625.     fRet=FLinksEnumerate(hList, pDoc, FEnumLinkFind,
  626.                          ENUMLINK_UNSELECTED, MAKELONG(pObj->aLink, 0));
  627.  
  628.     //If fRet is TRUE, there were no other matches.
  629.     if (fRet)
  630.         return TRUE;
  631.  
  632.     /*
  633.      * If we found a match, display a message asking if we want to update
  634.      * unselected links that match.
  635.      */
  636.  
  637.     //Ask the user if they want to update the rest to szFile.
  638.     GetAtomName(pObj->aLink, pDoc->pszData1, CBSCRATCH);
  639.     pszLinkFile=PszFileFromPath(pDoc->pszData1);
  640.     cch=lstrlen(pDoc->pszData1)+1;
  641.  
  642.     GetAtomName(pDoc->aFile, pDoc->pszData1+cch, CBSCRATCH-cch);
  643.     pszFile=PszFileFromPath(pDoc->pszData1+cch);
  644.  
  645.     psz=pDoc->pszData2;
  646.  
  647.     cch=wsprintf(psz, PSZOLE(IDS_UPDATELINKS1), pszLinkFile, pszFile);
  648.     wsprintf(psz+cch, PSZOLE(IDS_UPDATELINKS2), pszLinkFile);
  649.  
  650.     hWndParent=GetParent(hList);
  651.     wTemp=MessageBox(hWndParent, psz, PSZOLE(IDS_UPDATEMSG), MB_YESNO | MB_ICONEXCLAMATION);
  652.  
  653.     /*
  654.      * Mark all matching SELECTED files so we don't try to ask the
  655.      * user again for the same file.  This marks the one we're currently
  656.      * looking at, but that's not a problem.
  657.      */
  658.     FLinksEnumerate(hList, pDoc, FEnumLinkUpdate, ENUMLINK_SELECTED,
  659.                     MAKELONG(pObj->aLink, IDRETRY));
  660.  
  661.     //Update all matching unselected links.
  662.     if (IDYES==wTemp)
  663.         {
  664.         FLinksEnumerate(hList, pDoc, FEnumLinkUpdate, ENUMLINK_UNSELECTED,
  665.                         MAKELONG(pObj->aLink, IDIGNORE));
  666.         }
  667.     return TRUE;
  668.     }
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675.  
  676. /*
  677.  * FEnumLinkCancel
  678.  *
  679.  * Purpose:
  680.  *  Uses OleObjectConvert to change a linked object to a static object.
  681.  *  Note that this is much like the FEnumOptionChange function as it
  682.  *  changes an object to static instead of automatic or manual.
  683.  *
  684.  * Parameters:
  685.  *  hList           HANDLE to the links listbox.
  686.  *  i               WORD index of the item affected.
  687.  *  pDoc            LPDOCUMENT containing OLE information
  688.  *  pObj            LPOBJECT of the currently enumerated object.
  689.  *  dw              DWORD application supplied extra data
  690.  *
  691.  * Return Value:
  692.  *  BOOL            Always TRUE since we want to process all selected
  693.  *                  items.
  694.  */
  695.  
  696. BOOL FAR PASCAL FEnumLinkCancel(HWND hList, WORD i, LPDOCUMENT pDoc,
  697.                                 LPOBJECT pObj, DWORD dw)
  698.     {
  699.     OLESTATUS       os;
  700.     LPOLEOBJECT     pOLEObj;
  701.  
  702.     /*
  703.      * For any item that we cancel, call OleObjectConvert, set
  704.      * the dwLink field in the OBJECT to OLEUPDATE_STATIC, and delete the
  705.      * old object.  After this we can update the listbox to reflect the
  706.      * cancelled link.
  707.      */
  708.  
  709.     GetAtomName(pObj->aName, pDoc->pszData1, 80);
  710.     os=OleObjectConvert(pObj->pObj, PSZOLE(IDS_STATIC), (LPOLECLIENT)pObj,
  711.                         pDoc->lh, pDoc->pszData1, &pOLEObj);
  712.  
  713.     if (OLE_OK!=os)
  714.         return TRUE;
  715.  
  716.     //Delete the old object and wait on it.
  717.     os=OleDelete(pObj->pObj);
  718.  
  719.     if (OLE_OK==OsError(os, pDoc, pObj, TRUE))
  720.         {
  721.         //Set the new object in this window.
  722.         pObj->pObj   = pOLEObj;
  723.         pObj->dwLink = -1;
  724.         pObj->dwType = OT_STATIC;
  725.  
  726.         CchLinkStringCreate(pDoc->pszData1, pDoc, pObj);
  727.         LinkStringChange(hList, i, pDoc->pszData1);
  728.         pObj->fLinkChange=TRUE;
  729.         }
  730.  
  731.     return TRUE;
  732.     }
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740. /*
  741.  * FEnumLinkChange
  742.  *
  743.  * Purpose:
  744.  *  Changes the link data for an item, simply by calling FObjectDataGet
  745.  *  and then FObjectDataSet, which in turn calls OleSetData.
  746.  *
  747.  * Parameters:
  748.  *  hList           HANDLE to the links listbox.
  749.  *  i               WORD index of the item affected.
  750.  *  pDoc            LPDOCUMENT containing OLE information
  751.  *  pObj            LPOBJECT of the currently enumerated object.
  752.  *  dw              DWORD application supplied extra data.  The LOWORD
  753.  *                  is an ATOM containing the update filename.  If HIWORD
  754.  *                  is zero, we just update.  If it's non-zero then
  755.  *                  HIWORD is an ATOM containing the file to match
  756.  *                  before updating.  This latter use is for updating
  757.  *                  non-selected links that match.
  758.  *
  759.  * Return Value:
  760.  *  BOOL            Always TRUE since we want to process all items.
  761.  */
  762.  
  763. BOOL FAR PASCAL FEnumLinkChange(HWND hList, WORD i, LPDOCUMENT pDoc,
  764.                                 LPOBJECT pObj, DWORD dw)
  765.     {
  766.     /*
  767.      * If we're updating non-selected links, check if the files match
  768.      * and skip if they don't.  We have no bother to check selected
  769.      * links since the Change Link... button is grayed if all the selected
  770.      * items in the list are not linked to the same file.
  771.      */
  772.     if (0!=HIWORD(dw))
  773.         {
  774.         if ((ATOM)HIWORD(dw)!=pObj->aLink)
  775.             return TRUE;
  776.         }
  777.  
  778.     //Get the new link filename.
  779.     GetAtomName(LOWORD(dw), pDoc->pszData1, CCHPATHMAX);
  780.  
  781.     //Change this item's data and update the string
  782.     if (FObjectDataSet(pDoc, pObj, pDoc->cfObjectLink, pDoc->pszData1))
  783.         {
  784.         //Changing an unavailable link makes it automatic by default.
  785.         if (OLEUPDATE_UNAVAILABLE==pObj->dwLink)
  786.             pObj->dwLink=oleupdate_always;
  787.  
  788.         CchLinkStringCreate(pDoc->pszData1, pDoc, pObj);
  789.         LinkStringChange(hList, i, pDoc->pszData1);
  790.         pObj->fLinkChange=TRUE;
  791.         }
  792.  
  793.     return TRUE;
  794.     }
  795.  
  796.  
  797.  
  798.  
  799. /*
  800.  * FEnumLinkFind
  801.  *
  802.  * Purpose:
  803.  *  If the HIWORD of dw is 0, then this function compares an ATOM
  804.  *  containing a filename to the provided ATOM in the LOWORD of dw to
  805.  *  that stored in the object.  If they match, then the ObjectLink data
  806.  *  for the file is stored in pDoc->szData1 and this function returns FALSE,
  807.  *  stopping the enumeration.
  808.  *
  809.  *  If HIWORD(dw) is non-zero, we just get data for the first object we get.
  810.  *
  811.  * Parameters:
  812.  *  hList           HANDLE to the links listbox.
  813.  *  i               WORD index of the item affected.
  814.  *  pDoc            LPDOCUMENT containing OLE information
  815.  *  pObj            LPOBJECT of the currently enumerated object.
  816.  *  dw              DWORD application supplied extra data.
  817.  *
  818.  * Return Value:
  819.  *  BOOL            Always TRUE since we want to process all selected
  820.  *                  items.
  821.  */
  822.  
  823. BOOL FAR PASCAL FEnumLinkFind(HWND hList, WORD i, LPDOCUMENT pDoc,
  824.                               LPOBJECT pObj, DWORD dw)
  825.     {
  826.     //Continue enumeration if the atoms do not match.
  827.     if (0==HIWORD(dw))
  828.         {
  829.         if ((ATOM)LOWORD(dw)!=pObj->aLink)
  830.             return TRUE;
  831.         }
  832.  
  833.     FObjectDataGet(pObj, pDoc->cfObjectLink, pDoc->pszData1);
  834.     return FALSE;
  835.     }
  836.  
  837.  
  838.  
  839.  
  840. /*
  841.  * FEnumLinksUndo
  842.  *
  843.  * Purpose:
  844.  *  Checks if the object was modified in the links dialog and restores
  845.  *  its original state if so from the cloned object.  The object now stored
  846.  *  in the OBJECT structure is deleted with OleDelete.  If it was originally
  847.  *  open to a server, it is reconnected.
  848.  *
  849.  * Parameters:
  850.  *  hList           HANDLE to the links listbox.
  851.  *  i               WORD index of the item affected.
  852.  *  pDoc            LPDOCUMENT containing OLE information
  853.  *  pObj            LPOBJECT of the currently enumerated object.
  854.  *  dw              DWORD application supplied extra data.
  855.  *
  856.  * Return Value:
  857.  *  BOOL            Always TRUE since we want to process all selected
  858.  *                  items.
  859.  */
  860.  
  861. BOOL FAR PASCAL FEnumLinksUndo(HWND hList, WORD i, LPDOCUMENT pDoc,
  862.                                LPOBJECT pObj, DWORD dw)
  863.     {
  864.     OLESTATUS       os;
  865.     char            szObject[128];
  866.  
  867.  
  868.     //For unmodified links, nuke the clone.
  869.     if (!pObj->fLinkChange)
  870.         {
  871.         /*
  872.          * Note that in waiting for release we watch the fRelease flag
  873.          * in pObj, not the OLEOBJECT within the structure.  Since we
  874.          * called OleClone with the same OBJECT in which its stored, we'll
  875.          * get that OBJECT in the CallBack when we do release, if you
  876.          * just set a flag like Patron does.
  877.          */
  878.         os=OleDelete(pObj->pObjUndo);
  879.         OsError(os, pDoc, pObj, TRUE);
  880.         return TRUE;
  881.         }
  882.  
  883.     //Get the name of the object for OleRename on the clone.
  884.     GetAtomName(pObj->aName, szObject, 128);
  885.  
  886.     //Delete the old object.
  887.     os=OleDelete(pObj->pObj);
  888.     os=OsError(os, pDoc, pObj, TRUE);
  889.  
  890.     if (OLE_OK!=os)
  891.         return TRUE;
  892.  
  893.     pObj->pObj=pObj->pObjUndo;
  894.     pObj->pObjUndo=NULL;
  895.  
  896.     //Do this before reinitializing since the initializer calls OleQueryName.
  897.     OleRename(pObj->pObj, szObject);
  898.  
  899.     //Reinitialize this object's cache information.
  900.     PObjectInitialize(pObj, pDoc);
  901.  
  902.     //Attempt to reestablish a lost link for the clone.
  903.     if (pObj->fUndoOpen)
  904.         {
  905.         os=OleReconnect(pObj->pObj);
  906.         OsError(os, pDoc, pObj, TRUE);  //Wait
  907.         }
  908.  
  909.     /*
  910.      * This is a little sleazy, using the CallBack method for this object
  911.      * to force a repaint.  But it's actually kosher since the DS register
  912.      * will be correct (CallBack does not change it) and prevents us from
  913.      * having to find where this object is otherwise stored (as in a window).
  914.      */
  915.     (*pObj->pvt->CallBack)((LPOLECLIENT)pObj, OLE_CHANGED, pObj->pObj);
  916.  
  917.     return TRUE;
  918.     }
  919.  
  920.  
  921.  
  922.  
  923. /*
  924.  * FEnumLinksAccept
  925.  *
  926.  * Purpose:
  927.  *  Clean up any cloned objects when we accept changes in the Links dialog.
  928.  *
  929.  * Parameters:
  930.  *  hList           HANDLE to the links listbox.
  931.  *  i               WORD index of the item affected.
  932.  *  pDoc            LPDOCUMENT containing OLE information
  933.  *  pObj            LPOBJECT of the currently enumerated object.
  934.  *  dw              DWORD application supplied extra data.
  935.  *
  936.  * Return Value:
  937.  *  BOOL            Always TRUE since we want to process all selected
  938.  *                  items.
  939.  */
  940.  
  941. BOOL FAR PASCAL FEnumLinksAccept(HWND hList, WORD i, LPDOCUMENT pDoc,
  942.                                  LPOBJECT pObj, DWORD dw)
  943.     {
  944.     OLESTATUS       os;
  945.  
  946.     os=OleDelete(pObj->pObjUndo);
  947.     os=OsError(os, pDoc, pObj, TRUE);
  948.  
  949.     return TRUE;
  950.     }
  951.